/*
 * Copyright (c) 2010 Zauber S.A.  -- All rights reserved
 */
package ar.edu.itba.ia2010.geneticos.motor.api.sintaxistree.bitwise.visitors;

import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.UnhandledException;
import org.apache.commons.lang.Validate;

import ar.edu.itba.ia2010.geneticos.motor.api.sintaxistree.Expresion;
import ar.edu.itba.ia2010.geneticos.motor.api.sintaxistree.bitwise.AbstractTerminalExpresion;

/**
 * TODO Descripcion de la clase. Los comenterios van en castellano.
 * 
 * 
 * @author Juan F. Codagnone
 * @since Apr 2, 2010
 */
public class GraphvizVisitorCallback implements Expresion.VisitorCallback {
    private final Writer writer;
    
    /** constructor */
    public GraphvizVisitorCallback(final Writer writer) throws IOException {
        Validate.notNull(writer);
        
        this.writer = writer;
        
        writer.append("graph foo {\n");
        writer.append("\trankdir=RL;\n");
        writer.append("\tsize=\"8,5\"\n");
        writer.append("\n");
    }
    
    /** @see VisitorCallback#notify(Expresion) */
    public final Expresion notify(final Expresion e) {
        final Long id = getOrRegister(e);
        
        try {
            String name = e.getCharacter() + ""; 
            writer.append("\tx" + id + "[label=\"" + name  + "\"];\n");
            if(e instanceof  AbstractTerminalExpresion) {
                writer.append("\tx" + id + "[shape = doublecircle];\n");    
            }
            for(final Expresion childs : e) {
                final String s =  "\tx" + id + " --  x" + getOrRegister(childs) 
                + ";\n";
                if(!cache.contains(s)) {
                    cache.add(s);
                    writer.append(s);    
                }
            }
            lastId = id;
        } catch (final IOException e1) {
            throw new UnhandledException(e1);
        }
        return null;
    }
    
    /** debe llamarse luego del recorrido */ 
    public final void close() throws IOException {
        writer.append("\tx" + lastId 
                + "[shape = doublecircle,  fillcolor=salmon2];\n");
        cache.clear();
        map.clear();
        writer.append("}\n");
        writer.close();
    }

    private long lastId;
    private Set<String> cache = new HashSet<String>();
    private Map<Expresion, Long> map = new HashMap<Expresion, Long>();
    private long sequence;
    
    /** 
     * obtiene el id de la expresion (le asigna un nuevo id si nunca la vio 
     * pasar) */
    private Long getOrRegister(final Expresion e) {
        Long id = map.get(e);
        if(id == null) {
            id = sequence++;
            map.put(e, id);
        }
        return id;
    }

}
